<?php
/**
 * php GEM Project
 *
 * LICENSE
 *
 * PHP System Architecture Enabling Rapid Application Deployment and Scalability
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @copyright Copyright (C) 2010 Zeletron LLC (http://zeletron.com)
 * @license http://gem.zeletron.com/license
 */

/*
 * GEM/Service/User.php
 *
 *
 *
 * @author David Joly
 * @link http://zeletron.com
 *
 * @category GEM
 * @package GEM_Service
 */
class GEM_Service_User extends GEM_Service_Service
{
	/**
	 * Returns the Service Resource Id
	 *
	 * @return string
	 */
	public function getResourceId()
	{
		return 'UserService';
	}

	/**
	 * Returns the user with the specified username,
	 * if the user exists.
	 *
	 * @param string $username
	 * @return GEM_Model_Domain_User
	 */
	public function getByUsername($username)
	{
		return GEM_Model_Domain_User::getFinder('User')->findByUsername($username);
	}

	/**
	 * @param array $post
	 * @return GEM_Service_Response
	 */
	public function forgotPassword(array $post)
	{
		$form = new GEM_Form_UserForgotPasswordForm();
		if($form->isValid($post)){
			$user = GEM_Model_Domain_User::getFinder('User')->findByEmail($post["{$form->getFormName()}_email"]);
			if(is_null($user)){
				//User not found.
				$form->getElement("{$form->getFormName()}_email")->addError('Could not find a user with that email.');
				return $this->response(__FUNCTION__,self::RESPONSE_CODE_INVALID,null,$form);
			} else {
				//User found - Generate password, update user's password,
				//and send email to user.
				$password = GEM_Crypt::generatePassword();
				$user->setPassword(crypt($password));
				GEM_Model_Domain_ObjectManager::instance()->commit();

				/** @see GEM_Mail_Mailer#send() */
				$body = "Hello {$user->getFullname()}<p>Your new password is &quot;" . htmlentities($password) . "&quot;. "
				. '<a href="' . Zend_Registry::get('config')->base_url . '">Login</a> using this password.</p>';

				$mailOptions = array(
					'from'	=> array(
						'name' 	=> Zend_Registry::get('config')->email->from->name,
						'email'	=> Zend_Registry::get('config')->email->from->email
				),
					'to'	=> array($post["{$form->getFormName()}_email"]),
					'subject'	=> "Your new Password",
					'body'		=> $body
				);
				if(GEM_Mail_Mailer::send($mailOptions)){
					return $this->response(__FUNCTION__,self::RESPONSE_CODE_SUCCESS,'Please check your email for your new password.');
				} else {
					return $this->response(__FUNCTION__,self::RESPONSE_CODE_ERROR,"We're sorry. We could not send the email. Try again later.",$form);
				}
			}
		} else {
			return $this->response(__FUNCTION__,self::RESPONSE_CODE_INVALID,null,$form);
		}
	}

	/**
	 * @param array $post
	 * @return GEM_Service_Response
	 */
	public function login(array $post)
	{
		$form = new GEM_Form_UserLoginForm();
		if($form->isValid($post)){
			//Instantiate user object if user is found in database.
			$user = GEM_Model_Domain_User::getFinder('User')->findByEmail($post['userLoginForm_email']);
			if($user instanceof GEM_Model_Domain_User){
				//User found, authenticate user.
				if($user->getPassword() == crypt($post['userLoginForm_password'], $user->getPassword())){
					//Authentication successful. Save to session to log user into system.
					try {
						GEM_System::instance()->setUser($user);
					} catch (Exception $e) {
						Zend_Registry::get('logger')->log($e->getMessage());
						return $this->response(__FUNCTION__,self::RESPONSE_CODE_ERROR,'Could not start user session.');
					}
					return $this->response(__FUNCTION__,self::RESPONSE_CODE_SUCCESS);
				}
			}
		}
		//Form or credentials not valid...
		return $this->response(__FUNCTION__,self::RESPONSE_CODE_INVALID,'Login Failed',$form);
	}

	/**
	 * Clears the current user from the system.
	 *
	 * @return void
	 */
	public function logout()
	{
		if(GEM_System::hasUser()) GEM_System::clearUser();
	}

	/**
	 *
	 * @param array $post
	 * @return GEM_Service_Response
	 */
	public function signup(array $post)
	{
		$form = new GEM_Form_UserSignupForm();
		if($form->isValid($post)){
			//Create New User
			$user = new GEM_Model_Domain_User();
			$user->setUsername(strtolower($post["{$form->getFormName()}_username"]))
			->setFullname($post["{$form->getFormName()}_fullname"])
			->setEmail($post["{$form->getFormName()}_email"])
			->setLocale($post["{$form->getFormName()}_locale"])
			->setTimezone($post["{$form->getFormName()}_timezone"])
			->setPassword(crypt($post["{$form->getFormName()}_password"]));
			//Save new user to database
			if(GEM_Model_Domain_ObjectManager::instance()->commit() === false){
				return $this->response(__FUNCTION__,self::RESPONSE_CODE_ERROR,'An error occured during signup.');
			}
			//Save to session to log user into system
			try {
				GEM_System::instance()->setUser($user);
			} catch (Exception $e) {
				Zend_Registry::get('logger')->log($e->getMessage());
				return $this->response(__FUNCTION__,self::RESPONSE_CODE_ERROR,'Could not start user session.');
			}
			return $this->response(__FUNCTION__,
			self::RESPONSE_CODE_SUCCESS,
					"Welcome {$post["{$form->getFormName()}_fullname"]}. Here's your profile page. Click on the edit profile link to make changes."
			);
		} else {
			//Validation failed.
			return $this->response(__FUNCTION__,self::RESPONSE_CODE_INVALID,'Form Invalid. Please correct errors and resubmit.',$form,false);
		}
	}

	/**
	 * @param array $post
	 * @return return GEM_Service_Response
	 */
	public function update(array $post)
	{

		$form = new GEM_Form_UserUpdateForm();
		if($form->isValid($post)){

			//if($post['userUpdateForm_id'] == GEM_System::user()->getId()){
			//$user = GEM_System::user();
			//} else {
			$user = GEM_Model_Domain_User::getFinder('User')->find((int)$post['userUpdateForm_id']);
			//}
			//Verify user has permission to update profile...
			if( !GEM_System::hasUser() || !GEM_System::domainAcl()->isAllowed(GEM_System::user(),$user,'update')){
				return $this->response(__FUNCTION__,self::RESPONSE_CODE_DENIED,"You do not have permission to update this user's profile.");
			}
				
			//Creating backup of user object, in case a rollback is needed.
			$userBackup = clone($user);
			//If the password field has been changed, the confirm password field should match it.
			if($post['userUpdateForm_password'] != null && $post['userUpdateForm_password'] != ''){
				if($post['userUpdateForm_password'] != $post['userUpdateForm_confirmPassword']){
					$form->getElement('userUpdateForm_confirmPassword')->addError('Passwords must match.');
					return $this->response(__FUNCTION__,self::RESPONSE_CODE_INVALID,'Form Invalid. Please correct errors and resubmit.');
				}
			}

			//Handle file upload...
			if($form->userUpdateForm_newAvatar->isUploaded('userUpdateForm_newAvatar')){
				$path = PRIVATE_PATH . "/images/avatars/{$user->getId()}.jpg";
				$form->userUpdateForm_newAvatar->addFilter('Rename',array('target' => $path,'overwrite' => true));
				if(!$form->userUpdateForm_newAvatar->receive('userUpdateForm_newAvatar')){
					return $this->response(__FUNCTION__,self::RESPONSE_CODE_ERROR,'There was an error receiving your image file.');
				} else {
					//File received successfully...
					if($user->getAvatar()->getFilename() == 'default'){
						//If the user is changing from the default avatar, a new
						//image object is created. If the user is not currently
						//using the default avatar, their current avatar file is
						//simply overwritten.
						$user->setAvatar(new GEM_Model_Domain_Image(null,$path));
						//Set user as owner of avatar image file...
						$user->getAvatar()->setOwner($user);
					} else {
						//Clear existing image from object if in object
						$user->getAvatar()->init($path);
					}
				}
			}
				
			//Update user...
			$user->setUsername($post['userUpdateForm_username'])
			->setFullname($post['userUpdateForm_fullname'])
			->setInfo($post['userUpdateForm_info'])
			->setEmail($post['userUpdateForm_email'])
			->setTimezone($post['userUpdateForm_timezone'])
			->setLocale($post['userUpdateForm_locale']);
			if(array_key_exists('userUpdateForm_password',$post) && !empty($post['userUpdateForm_password'])){
				$user->setPassword(crypt($post['userUpdateForm_password']));
			}
				
			//Handle social...
			$social = array();
			foreach($post['userUpdateForm_social'] as $type => $value){
				if(!empty($value)) $social[$type] = $value;
			}
			$user->setSocial($social);

			if(GEM_Model_Domain_ObjectManager::instance()->commit() === false){
				//An error occurred during update. All transactions rolled back. Resetting user object...
				GEM_System::setUser($userBackup);
				GEM_Model_Domain_ObjectManager::instance()->register($userBackup);
				return $this->response(__FUNCTION__,self::RESPONSE_CODE_ERROR,'The system encountered an error while trying to update profile.');
			}
			return $this->response(__FUNCTION__,self::RESPONSE_CODE_SUCCESS,'Profile updated successfully');
		} else {
			//Validation failed.
			return $this->response(__FUNCTION__,self::RESPONSE_CODE_INVALID,'Form Invalid. Please correct errors and resubmit.');
		}
	}

	/**
	 * Returns a user login form for rendering
	 *
	 * @param string $action | The form's action attribute
	 * @param string $method | The form's method attribute
	 * @return GEM_Form_UserLoginForm
	 */
	public function loginForm($action = '/auth/login/',$method = 'post')
	{
		$form = new GEM_Form_UserLoginForm();
		$form->setAction($action)
		->setMethod($method);
		return $form;
	}

	/**
	 * Returns a user signup form for rendering
	 *
	 * @param string $action | The form's action attribute
	 * @param string $method | The form's method attribute
	 * @return GEM_Form_UserSignupForm
	 */
	public function signupForm($action = '/accounts/signup/',$method = 'post')
	{
		$form = new GEM_Form_UserSignupForm();
		$form->setAction($action)
		->setMethod($method);
		return $form;
	}

	/**
	 * Returns a forgot password form for rendering
	 *
	 * @param string $action | The form's action attribute
	 * @param string $method | The form's method attribute
	 * @return GEM_Form_UserForgotPasswordForm
	 */
	public function forgotPasswordForm($action = '/accounts/forgotpassword/',$method = 'post')
	{
		$form = new GEM_Form_UserForgotPasswordForm();
		$form->setAction($action)
		->setMethod($method);
		return $form;
	}

	/**
	 * Returns a update user form for rendering
	 *
	 * @param GEM_Model_Domain_User $user | The user with which to populate the form's data
	 * @param string $action | The form's action attribute
	 * @param string $method | The form's method attribute
	 * @return GEM_Form_UserForgotPasswordForm
	 */
	public function updateForm($user, $action = '/accounts/processprofile', $method = 'post')
	{
		$form = new GEM_Form_UserUpdateForm();
		//Social Data
		$form->setAction($action)
		->setMethod($method)
		->populate(array(
				"{$form->getFormName()}_id" => $user->getId(),
				"{$form->getFormName()}_username" => $user->getUsername(),
				"{$form->getFormName()}_fullname" => $user->getFullname(),
				"{$form->getFormName()}_email" => $user->getEmail(),
				"{$form->getFormName()}_confirmEmail" => $user->getEmail(),
				"{$form->getFormName()}_info" => $user->getInfo(),
				"{$form->getFormName()}_timezone" => $user->getTimezone(),
				"{$form->getFormName()}_locale" => $user->getLocale(),
				"{$form->getFormName()}_social" => $user->getSocial()				
		));
		return $form;
	}
}